require "Battle/Manager/FightManager"
require "Battle/Manager/ClientFightManager"
require "Battle/Manager/EntityAiManager"

UILoadingBattle = {};
HelperFunc.SetUIEnv(UILoadingBattle)
local this = UILoadingBattle;

this.LuaBehaviour = nil;
this.transform = nil;

this.hasInit = false;
this.func = nil;
this.res = nil;
this.progress = nil;
this.load_txt = nil;
this.roleCfg = nil
this.index = nil
this.timerId = nil
this.delayTime = nil
this.contenIds = {}
this.loadingStartTime = 0

function UILoadingBattle.Init(resList, callback, isNew)
    local name, packageName = getUIName(PanelNames.UILoadingBattle);
    this.callback = callback;
    this.res = resList;
    this.isNew = isNew
    panelMgr:ShowUI(name, packageName, this.onCreate, Config.useLocalUI);
end

function UILoadingBattle.onCreate(obj)
    if not hasInit then
        --HelperFunc.UnloadUnusedAssets(EnumConst.ClearType.ALL)
        hasInit = true;
        roleCfg = G.dataTable["t_roleinfo"]
        delayTime = tonumber(G.dataTable["t_global"]["403"].f_string_value)
        contenIds = FightManager.GetsloadContentId()
        --BG = transform:Find("BG"):GetComponent("Image");
        progress = obj:GetChild("Img_Progress");
        load_txt = obj:GetChild("TextLoading")
        local ctrlPA = obj:GetController("PA")
        if ctrlPA then
            if AppConst.drawingState == 0 then
                ctrlPA.selectedIndex = 0
            else
                ctrlPA.selectedIndex = 1
            end
        end
        this.addEvent();
        this.progress.value = 100 - 0
        this.step = 1
        this.needLoadResList = {}
        this.needLoadResCount = 0
        this.curLoadCount = 0
        for k, v in pairs(this.res) do
            this.needLoadResList[k] = v
            this.needLoadResCount = this.needLoadResCount + 1

        end
        this.res = nil
        utimer.delayCall(function()
            UILoadingBattle.HideCityUI();
        end,1)
        showUI(PanelNames.UIBloodBar);
        this.LocalLoadResource()
        logicMgr.GuideMgr.DestroySoft()
    end	
	if #contenIds >0 then
		index = math.random(#contenIds)
		load_txt.text = getLanguage(roleCfg[tostring(contenIds[index])].f_LoadingText)
		utimer.delayCall(function() 
		    this.ShowText()
        end,1000
        )
	end
end

function UILoadingBattle.ShowText()
    utimer.remove(timerId)
    timerId = utimer.timeCall(function()
        if index == #contenIds then
            index = 1
        else
            index= index+1
        end
        if load_txt then
            load_txt.text = getLanguage(roleCfg[tostring(contenIds[index])].f_LoadingText)
        end
    end,1000*delayTime,-1)
end

function UILoadingBattle.LocalLoadResource()
    --log("UILoadingBattle.loadResource");

    BattleSceneCacheResouce:ClearCacheRes(this.needLoadResList)
    this.loading = false
    this.DelLoadTimer()
    local statePercent = { 70, 30 }
    --statePercent[1] = 100
    --
    local bossMap = logicMgr.MapManager.getBossMapName();
    local fightType = BattlePlaybackManager.GetFightType();
    if fightType == EnumConst.FightTypeConst.TRIAL then
        bossMap = logicMgr.TrialsManager.GetTrialsConfig()[tostring(logicMgr.TrialsManager.GetTrialsInfo().trialsId)].f_BattleMap;
    elseif fightType == EnumConst.FightTypeConst.ARENA then
        bossMap = G.dataTable["t_global"]["134"].f_string_value;
    elseif fightType == EnumConst.FightTypeConst.INSTANCE then
        bossMap = logicMgr.MythicDungeonsProManager.GetLayerMapName()
    elseif fightType == EnumConst.FightTypeConst.TOWER then
        bossMap = logicMgr.TowerManager.getBattleMapId();
    elseif fightType == EnumConst.FightTypeConst.Expedition then
        bossMap = ExpeditionMapMgr.GetMapName()
    elseif fightType == EnumConst.FightTypeConst.StoryBattle then
        bossMap = logicMgr.StoryHardManager.getBattleMapName()
    end
    local mapInstance = BattleSceneCacheResouce:GetMapInstance()	
    --if #FightManager.GetsloadContentId()>0 and mapInstance and (mapInstance.name == bossMap .. "(Clone)" or bossMap == "") then
    --    BattleSceneCacheResouce:InitMapInstance(mapInstance, true)
    --else
        this.needLoadResList["Prefabs/MapPref/" .. bossMap] = "Map"
        destroy(mapInstance)
        BattleSceneCacheResouce:SaveMapInstance(nil)
    --end
    if logicMgr.FuncOpenManager.isOpen(Config.FuncOpenType.City,false) and panelMgr:GetUI("UICity") == nil then
        this.needLoadResList[PanelResNames.UICity] = "UI"
    end
    ---@type UILoadingBattle_StateMachine
    this.stateMachine = UILoadingBattle_StateMachine.New()
    this.stateMachine:AddState(UILoadingBattle_LoadStateBase.New(1, statePercent[1], this.needLoadResList, this.UpdateProgress))
    if this.isNew then
        this.stateMachine:AddState(UILoadingBattle_LoadStateBase.New(2, statePercent[2], nil, this.UpdateProgress))
    end
    this.stateMachine:FailedLimitTime(20)
    this.stateMachine:OnComplete(this.LoadFinish)
    this.stateMachine:Start()

    --界面未加载，已收到消息
    if BattlePlaybackManager.IsReceiveReport() then
        this.AddLoadingResourceMsg(FightManager.resList)
    end
end
function UILoadingBattle.UpdateProgress(percent)
    this.progress.value = this.progress.value - percent
end
function UILoadingBattle.HideCityUI()
    destroyAllUIIgnore(function(name)
        if getUIName(name) == getUIName(PanelNames.UILoadingBattle) or getUIName(name) == getUIName(PanelNames.UICover) then
            return true
        else
            if IsNoDelete(name) then
                closeUI(name)
                return true
            else
                return false
            end
        end
    end)
    UIRedDots.Destory()
end

function UILoadingBattle.addEvent()
    ListenEvent(Config.EventType.LoadingCancelByFightError, this.FightErrorMsg)
    ListenEvent(Config.EventType.AddLoadingLoadResource, this.AddLoadingResourceMsg)
end

function UILoadingBattle.removeEvent()
    CloseEvent(Config.EventType.AddLoadingLoadResource, this.AddLoadingResourceMsg)
    CloseEvent(Config.EventType.LoadingCancelByFightError, this.FightErrorMsg)
end

function UILoadingBattle.OnDestroy()
    this.removeEvent();
    this.DelLoadTimer()
    if this.stateMachine then
        this.stateMachine:OnDestroy()
    end
    this.stateMachine = nil
    this.needLoadResList = nil
    this.callback = nil
    this.loading = false
    this.hasInit = false
    if timerId then
        utimer.remove(timerId)
        timerId = nil
    end

    --HelperFunc.UnloadUnusedAssets()--界面关闭时，GC卡顿太明显
end

function UILoadingBattle.OnEnable()
    utimer.delayCall(function()
        local ctrlItem = CtrlManager.GetCtrl(PanelNames.TeamHeroItem)
        ctrlItem.CacheHeros()
    end,1)
end

function UILoadingBattle.OnDisable()
    if timerId then
        utimer.remove(timerId)
        timerId = nil
    end
end

function UILoadingBattle.DelLoadTimer()
    if this.loadTimer then
        utimer.remove(this.loadTimer)
        this.loadTimer = nil
    end
end
function UILoadingBattle.FightErrorMsg(msg)
    printError("请求战报失败，网络原因===")
    this.LoadFinish(false, msg)
end
function UILoadingBattle.AddLoadingResourceMsg(resList)
    if not resList then
        return
    end
    if this.stateMachine == nil then return end
    local state = this.stateMachine:GetState(2)
    if state == nil then
        return
    end
    local diffList = {}
    local count = 0
    for k, v in pairs(resList) do
        if not this.needLoadResList[k] then
            diffList[k] = v
            count = count + 1
        end
    end

    if count == 0 then
        state:FinishImmediate()
    else
        state:SetLoadRes(diffList)
    end
    log("战报返回后，2阶段需要加载的数量"..count.."===2阶段剩余时间"..this.stateMachine.failedLimitTime)
    BattlePlaybackManager.ResetReceiveReport()
end
function UILoadingBattle.LoadFinish(success, msg)
    --战斗loading事件埋点
    local _loadingEndTime = HelperFunc.GetServerTime(false)
    local _loadingDic = {}
    _loadingDic.duration = _loadingEndTime - this.loadingStartTime
    _loadingDic.source = FightManager.fightType
    _loadingDic.is_success = success
    _loadingDic.info_ex = -1
    TAManager.TrackByDictionary("fight_loading",_loadingDic)
    this.loadingStartTime = 0
    logicMgr.BattlePlaybackManager.CancelRepeatRequest()
    if success then
        this.progress.value = 100 - 100 ;
        this.callback()
    else
        if msg == nil then
            msg = "请求战报失败:"..tostring(logicMgr.BattlePlaybackManager.FightId)
        end
        if logicMgr.BattlePlaybackManager.IsReceiveResult() then
            logicMgr.BattlePlaybackManager.SetShowBattleResultImmediate(true)
            closeUI(PanelNames.UILoadingBattle)
            FightManager.showResultUI(true)
            printError(msg)
            UISysTips.AddMsg(getLanguage("ErrorCode_220004"))
            return
        end
        function FailOperation()
            FightManager.closeFight(FightManager.fightType);
            printError(msg)
            UISysTips.AddMsg(msg)
        end
        if _loadingDic.duration > 1000 then
            FailOperation();
        else
            utimer.delayCall(function()
                FailOperation();
            end,1000)
        end
    end

end
---@class UILoadingBattle_StateMachine
UILoadingBattle_StateMachine = Class()
function UILoadingBattle_StateMachine:ctor()
    self.stateList = {}
    self.cur = 1
    self.failedLimitTime = -1
end
function UILoadingBattle_StateMachine:OnDestroy()
    utimer.remove(self.updateTimer)
    self.updateTimer = nil
    if self.stateList then
        for k, v in pairs(self.stateList) do
            v:Leave()
        end
    end
    self.stateList = nil
end
function UILoadingBattle_StateMachine:AddState(state)
    table.insert(self.stateList, state)
end
---@return UILoadingBattle_LoadStateBase
function UILoadingBattle_StateMachine:GetState(index)
    return self.stateList[index]
end
function UILoadingBattle_StateMachine:OnComplete(callback)
    self.completeCallback = callback
end
function UILoadingBattle_StateMachine:FailedLimitTime(time)
    self.failedLimitTime = time
end
function UILoadingBattle_StateMachine:Start()
    utimer.remove(self.updateTimer)
    this.loadingStartTime = HelperFunc.GetServerTime(false)
    self.updateTimer = utimer.frameCall(function()
        self:Update()
    end, -1)
end
function UILoadingBattle_StateMachine:Update()
    local curState = self.stateList[self.cur]
    if curState == nil then
        if self.completeCallback then
            self.completeCallback(true)
        end
        utimer.remove(self.updateTimer)
        self.updateTimer = nil
        return
    end
    if curState.isFinished then
        curState:Leave()
        self.cur = self.cur + 1
    elseif not curState.isEnter then
        curState:Enter()
    else
        curState:Update()
    end
    if self.failedLimitTime ~= -1 then
        self.failedLimitTime = self.failedLimitTime - Time.deltaTime
        if self.failedLimitTime <= 0 then
            local flag = logicMgr.BattlePlaybackManager.IsReceiveReport()
            printError("进入战斗Loading，资源加载资源超时===receiveReport:"..tostring(flag))
            if self.completeCallback then
                self.completeCallback(logicMgr.BattlePlaybackManager.IsReceiveReport())
            end
            self.failedLimitTime = -1
            utimer.remove(self.updateTimer)
            self.updateTimer = nil
        end
    end
end
---@class UILoadingBattle_LoadStateBase
UILoadingBattle_LoadStateBase = Class()
function UILoadingBattle_LoadStateBase:ctor(type, percent, resList, loadProgressFunc)
    self.type = type
    self.percent = percent
    self.percentRate = 0
    self.resList = {}
    self.typeList = {}
    self.totalLoadCount = 0
    self.loadProgressFunc = loadProgressFunc
    self.isEnter = false
    self.isLeave = false
    self.isFinished = false
    self.frameLoadCount = 5
    self.isImmediate = false
    self:SetLoadRes(resList)
end

function UILoadingBattle_LoadStateBase:Enter()
    self.isEnter = true
    self.curLoadIndex = 0
    self.curLoadedCount = 0
end
function UILoadingBattle_LoadStateBase:Leave()
    if self.isLeave then
        return
    end
    self.isLeave = true
    if self.isImmediate then
        self:ProgressCallback()
    end
end
function UILoadingBattle_LoadStateBase:Update()
    if self.isFinished then
        return
    end
    if self.curLoadIndex >= self.totalLoadCount then
        return
    end
    local _end = self.curLoadIndex + 1 + self.frameLoadCount
    for i = self.curLoadIndex + 1, _end do
        local resName = self.resList[i]
        local type = self.typeList[i]
        if resName == nil then
            break
        end
        log("load res *********"..resName)
        loadResource2(resName, type, function(prefabobj)
            log("load res success=="..resName)
            if type == "Effect" then 
                local obj_name = nil
                local ret = string.match(resName,"/[^/]*[^/]$")
                if ret ~= nil then
                    obj_name = string.gsub(ret, "/", "") 
                    -- print("------------------------->resName:", resName, " prefabobj.name:", prefabobj.name, "obj_name:", obj_name)
                end
                SpineEffectManager.createEffectPool(panelMgr.BattleRound.transform, prefabobj, 1, obj_name)
            elseif type == "Model" then
            elseif type == "Map" then
                local mapInstanse = newObject(prefabobj);
                BattleSceneCacheResouce:InitMapInstance(mapInstanse, true)
            elseif type == "FlyText" then
                objectPoolMgr:CreatePool(prefabobj.name, 2, 5, prefabobj);
            elseif type == "UI" then
                prefabobj.visible = false
            end
            self.curLoadedCount = self.curLoadedCount + 1
            self:ProgressCallback()
            if self.curLoadedCount == self.totalLoadCount then
                log("资源加载结束,数量===", self.curLoadedCount)
                self.isFinished = true
            end
        end);
    end
    self.curLoadIndex = _end
end
function UILoadingBattle_LoadStateBase:FinishImmediate()
    self.isFinished = true
    self.isImmediate = true
    self.percentRate = self.percent
end
function UILoadingBattle_LoadStateBase:SetLoadRes(resList)
    if resList == nil then
        return
    end
    for k, v in pairs(resList) do
        table.insert(self.resList, k)
        table.insert(self.typeList, v)
    end
    self.totalLoadCount = #self.resList
    if self.totalLoadCount == 0 then
        self:FinishImmediate()
    else
        self.percentRate = self.totalLoadCount == 0 and 0 or self.percent / self.totalLoadCount
    end
end
function UILoadingBattle_LoadStateBase:ProgressCallback()
    if self.loadProgressFunc then
        self.loadProgressFunc(self.percentRate)
    end
end
return UILoadingBattle;